package org.jsola.hr.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.logging.log4j.util.Strings;
import org.jsola.common.DateKit8;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IPolicyCourierDAO;
import org.jsola.hr.dto.*;
import org.jsola.hr.entity.PolicyCourierDO;
import org.jsola.hr.entity.PolicyPermissionsDO;
import org.jsola.hr.query.PolicyCourierQuery;
import org.jsola.hr.service.ICompanyService;
import org.jsola.hr.service.IGroupCompanyService;
import org.jsola.hr.service.IPolicyCourierService;
import org.jsola.hr.vo.PolicyCourierListVO;
import org.jsola.hr.vo.PolicyCourierVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 政策速递
 *
 * @author zhr
 */
@Service("hrPolicyCourierServiceImpl")
public class PolicyCourierServiceImpl implements IPolicyCourierService {

    @Autowired
    private IPolicyCourierDAO policyCourierDAO;

    @Autowired
    private PolicyPermissionsServiceImpl policyPermissionsService;

    @Autowired
    private IGroupCompanyService groupCompanyService;

    @Autowired
    private ICompanyService companyService;

    private final String GROUP = "group";

    private final String COMPANY = "company";

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public PolicyCourierVO save(PolicyCourierAddDTO policyCourierAddDTO, TokenUser tokenUser) {
        // 转DO
        PolicyCourierDO policyCourierDO = policyCourierAddDTO.to(PolicyCourierDO.class);
        List<CompanyTypeDTO> companyTypeList = policyCourierAddDTO.getCompanyTypeList();
        if (!CollectionUtils.isEmpty(companyTypeList)) {
            policyCourierDO.setCompanyPermissionsJson(JSON.toJSONString(companyTypeList));
        }
        // 把所选的用工单位分组变成用工单位id列表和所选的用工单位合起来再存下来,查询的时候好查询
        List<String> companyGroupIdList = companyTypeList.stream()
                .filter(type -> GROUP.equals(type.getType()))
                .map(CompanyTypeDTO::getId).collect(Collectors.toList());
        List<String> companyIdList = companyTypeList.stream()
                .filter(type -> COMPANY.equals(type.getType()))
                .map(CompanyTypeDTO::getId).collect(Collectors.toList());
        List<String> companyPermissionsIdList = this
                .addCompanyPermissions(companyGroupIdList, companyIdList, tokenUser.getSiteId());
        policyCourierDO.setCompanyPermissions(String.join(",", companyPermissionsIdList));
        List<PolicyCourierDO> allPolicyCourier = selectPolicyCourierBySite(tokenUser);
        Integer maxSort = allPolicyCourier.stream().map(PolicyCourierDO::getSort).max(Integer::compare).orElse(1);
        policyCourierDO.setSort(maxSort + 1);
        // 保存
        policyCourierDO = save(policyCourierDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 再保存权限
        this.savePolicyPermissions(policyCourierDO.getId(), companyGroupIdList, companyIdList, tokenUser);
        return policyCourierDO.to(PolicyCourierVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(PolicyCourierUpdateDTO policyCourierUpdateDTO, TokenUser tokenUser) {
        //转DO
        PolicyCourierDO policyCourierDO = policyCourierUpdateDTO.to(PolicyCourierDO.class);
        List<CompanyTypeDTO> companyTypeList = policyCourierUpdateDTO.getCompanyTypeList();
        policyCourierDO.setCompanyPermissionsJson(
                CollectionUtils.isEmpty(companyTypeList) ? "" : JSON.toJSONString(companyTypeList));
        List<String> companyGroupIdList = companyTypeList.stream()
                .filter(type -> GROUP.equals(type.getType()))
                .map(CompanyTypeDTO::getId).collect(Collectors.toList());
        List<String> companyIdList = companyTypeList.stream()
                .filter(type -> COMPANY.equals(type.getType()))
                .map(CompanyTypeDTO::getId).collect(Collectors.toList());
        List<String> companyPermissionsIdList = this
                .addCompanyPermissions(companyGroupIdList, companyIdList, tokenUser.getSiteId());
        policyCourierDO.setCompanyPermissions(String.join(",", companyPermissionsIdList));
        //根据主键更新，只更新非null值
        int updateCount = updateByIdSelective(policyCourierDO, tokenUser.getSiteId(), tokenUser.getUserId());
        if (updateCount == 0) {
            throw new ParamException("更新失败，请刷新页面后重试");
        }
        // 把之前的权限删除,再添加一边更新后的权限,做更新前后的权限是否一样的校验太麻烦了,所以这里直接删了再加
        policyPermissionsService.deleteByPolicyId(policyCourierUpdateDTO.getId(), tokenUser.getSiteId());
        // 重新添加
        this.savePolicyPermissions(policyCourierDO.getId(), companyGroupIdList, companyIdList, tokenUser);
        return updateCount;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... policyCourierIds) {
        for (String policyCourierId : policyCourierIds) {
            policyPermissionsService.deleteByPolicyId(policyCourierId, tokenUser.getSiteId());
        }
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) policyCourierIds);
    }


    @Override
    public PolicyCourierVO selectById(String policyCourierId, String siteId) {
        PolicyCourierDO policyCourierDO = selectDOById(policyCourierId, siteId);
        if (policyCourierDO == null) {
            return null;
        }
        return policyCourierDO.to(PolicyCourierVO.class);
    }

    @Override
    public List<PolicyCourierListVO> select(PolicyCourierQuery policyCourierQuery, String siteId) {
        List<PolicyCourierDO> policyCourierDOList = selectDO(policyCourierQuery, siteId);
        if (CollectionUtils.isEmpty(policyCourierDOList)) {
            return policyCourierDOList == null ? null : new ArrayList<>();
        }
        return policyCourierDOList.stream()
                .map(policyCourierDO -> policyCourierDO.to(PolicyCourierListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(PolicyCourierQuery policyCourierQuery, String siteId) {
        Example example = buildExample(policyCourierQuery, siteId);
        return policyCourierDAO.selectCountByExample(example);
    }

    @Override
    public Page<PolicyCourierListVO> selectPage(PolicyCourierQuery query, TokenUser tokenUser) {
        query.setUnion(true);
        TypeAndId typeAndId = query.getTypeAndId();
        // 从管理后台进入政策速递会有这个参数
        // type 会有三种类型  group,company 和site
        // id 对应的则是 type 是 group 或者 company 下的用工单位分组的Id和 用工单位Id type 为 site 时 id 为 0
        if (!ObjectUtils.isEmpty(typeAndId)) {
            String type = typeAndId.getType();
            if (GROUP.equals(type)) {
                List<String> groupCompanyIdList = groupCompanyService
                        .selectCompanyIdsByGroupIds(Collections.singletonList(typeAndId.getId()), tokenUser.getSiteId());
                groupCompanyIdList.add(typeAndId.getId());
                query.setCompanyIdList(groupCompanyIdList);
            } else if (COMPANY.equals(type)) {
                query.setCompanyId(typeAndId.getId());
            } else {
                // 如果是租户
                List<String> companyIdList = companyService.tileCompanyIdByUser2(tokenUser);
                query.setUnion(false);
                // 如果有全部权限不用管直接查询所有的政策速递,但是如果只有部分权限需要过滤自己的权限
                if (!"all".equals(companyIdList.get(0))) {
                    query.setCompanyIdList(companyIdList);
                    query.setUnion(true);
                }
            }
        }
        PageInfo<PolicyCourierListVO> pageInfo = PageHelper.startPage(query.getPageNo(), query.getPageSize())
                .doSelectPageInfo(() -> policyCourierDAO.selectPolicyCourier(query, tokenUser.getSiteId()));
        Page<PolicyCourierListVO> resultPage = new Page<>(pageInfo.getList(), pageInfo.getPageNum(),
                pageInfo.getPageSize(), (int) pageInfo.getTotal());
        List<PolicyCourierListVO> policyCourierList = resultPage.getEntities();
        if (!CollectionUtils.isEmpty(policyCourierList)) {
            for (PolicyCourierListVO policyCourier : policyCourierList) {
                String permissionsAdd = policyCourier.getPermissionsAdd();
                if (!StringUtils.isEmpty(permissionsAdd)) {
                    policyCourier.setGroupAndCompanyIdList(Arrays.asList(permissionsAdd.split(",")));
                }
                if (!StringUtils.isEmpty(policyCourier.getCompanyPermissionsJson())) {
                    policyCourier.setCompanyTypeList(JSON.parseArray(
                            policyCourier.getCompanyPermissionsJson(), CompanyTypeDTO.class));
                }
            }
        }
        return resultPage;
    }

    @Override
    public PolicyCourierDO selectDOById(String policyCourierId, String siteId) {
        return listById(policyCourierId, siteId);
    }

    @Override
    public List<PolicyCourierDO> selectDO(PolicyCourierQuery policyCourierQuery, String siteId) {
        Example example = buildExample(policyCourierQuery, siteId);
        return policyCourierDAO.selectByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void updateSort(List<UpdatePolicySortDTO> updateSortList) {
        if (!CollectionUtils.isEmpty(updateSortList)) {
            List<PolicyCourierDO> updateList = updateSortList.stream()
                    .map(updateSort -> updateSort.to(PolicyCourierDO.class))
                    .collect(Collectors.toList());
            for (PolicyCourierDO policyCourier : updateList) {
                policyCourierDAO.updateByPrimaryKeySelective(policyCourier);
            }
        }
    }

    @Override
    public void deleteByCode(String code, TokenUser tokenUser) {
        PolicyCourierDO policyCourier = new PolicyCourierDO();
        policyCourier.setValid(false);
        Example example = new Example(PolicyCourierDO.class);
        example.and()
                .andEqualTo("typeCode", code)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        policyCourierDAO.updateByExampleSelective(policyCourier, example);
    }

    @Override
    public void updatePolicyCourierCode(String newCode, String oldCode, TokenUser tokenUser) {
        PolicyCourierDO policyCourier = new PolicyCourierDO();
        policyCourier.setTypeCode(newCode);
        Example example = new Example(PolicyCourierDO.class);
        example.and()
                .andEqualTo("typeCode", oldCode)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        policyCourierDAO.updateByExampleSelective(policyCourier, example);
    }

    @Override
    public List<PolicyCourierDO> selectPolicyCourierBySite(TokenUser tokenUser) {
        Example example = new Example(PolicyCourierDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        return policyCourierDAO.selectByExample(example);
    }

    /**
     * 保存或更新政策速递时更新权限
     */
    private void savePolicyPermissions(String policyId, List<String> companyGroupIdList,
                                       List<String> companyIdList, TokenUser tokenUser) {
        List<PolicyPermissionsDO> bachSavePermissionsList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(companyGroupIdList)) {
            // 用工单位分组
            for (String companyGroupId : companyGroupIdList) {
                PolicyPermissionsDO save = new PolicyPermissionsDO();
                save.setPolicyId(policyId);
                save.setPermissionsType("group");
                save.setPermissionsId(companyGroupId);
                save.preInsert(tokenUser.getUserId());
                save.setSiteId(tokenUser.getSiteId());
                bachSavePermissionsList.add(save);
            }
        }
        if (!CollectionUtils.isEmpty(companyIdList)) {
            companyIdList = companyIdList.stream().distinct().collect(Collectors.toList());
            // 用工单位
            for (String companyId : companyIdList) {
                PolicyPermissionsDO save = new PolicyPermissionsDO();
                save.setPolicyId(policyId);
                save.setPermissionsType("company");
                save.setPermissionsId(companyId);
                save.preInsert(tokenUser.getUserId());
                save.setSiteId(tokenUser.getSiteId());
                bachSavePermissionsList.add(save);
            }
        }
        policyPermissionsService.bachSave(bachSavePermissionsList);
    }

    /**
     * 保存或更新政策速递查询用工单位权限
     */
    private List<String> addCompanyPermissions(List<String> companyGroupIdList, List<String> companyIdList, String siteId) {
        List<String> companyPermissionsIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(companyGroupIdList)) {
            companyPermissionsIdList = groupCompanyService.selectCompanyIdListByGroupIds(companyGroupIdList, siteId);
        }
        if (!CollectionUtils.isEmpty(companyIdList)) {
            companyPermissionsIdList.addAll(companyIdList);
        }
        return companyPermissionsIdList;
    }

    /**
     * 根据查询参数，构建example
     *
     * @param policyCourierQuery 查询参数
     * @param siteId             所属站点id
     * @return example
     */
    private Example buildExample(PolicyCourierQuery policyCourierQuery, String siteId) {
        Example example = new Example(PolicyCourierDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (!StringUtils.isEmpty(policyCourierQuery.getTitle())) {
            example.and().andLike("title", "%" + policyCourierQuery.getTitle() + "%");
        }
        if (!StringUtils.isEmpty(policyCourierQuery.getPolicyLevel())) {
            example.and().andEqualTo("policyLevel", policyCourierQuery.getPolicyLevel());
        }
        if (!StringUtils.isEmpty(policyCourierQuery.getTypeCode())) {
            example.and().andEqualTo("typeCode", policyCourierQuery.getTypeCode());
        }
        // 排序
        ExampleKit.setExampleOrder(example, policyCourierQuery.getOrders());
        return example;
    }
}




